/****************************************************************************
 * Copyright (C) 2011 Maxim Integrated Products, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL MAXIM INTEGRATED PRODUCTS BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Maxim Integrated Products
 * shall not be used except as stated in the Maxim Integrated Products
 * Branding Policy.
 *
 * The mere transfer of this software does not imply any licenses
 * of trade secrets, proprietary technology, copyrights, patents,
 * trademarks, maskwork rights, or any other form of intellectual
 * property whatsoever. Maxim Integrated Products retains all ownership rights.
 *
 *     Description: MAXQ SPI driver
 *             $Id: maxq_spi.c 3272 2012-02-27 20:28:47Z jbrodt $
 *
 ********************************************************************************
 */

#include <stddef.h>
#include "maxq_config.h"
#include "maxq_spi.h"
#include "maxq_spi_priv.h"

/***** Definitions *****/


/***** Function Prototypes *****/


/***** Global Data *****/
extern spi_t spi0;
extern spi_t spi1;


/****************************************************************************
* Description: Checks SPI flags and handles appropriately. Called by ISR for
*     interrupt driven strategy or can be called periodically by application.
* Parameters: none
* Returns: void
****************************************************************************/
void spi_handler(void)
{
#if ( (SPI0_RXB_LEN > 0) || (SPI1_RXB_LEN > 0) )
  uint16_t data;
#endif

  //*** SPI0 ***
#if (NUM_SPI > 0)
    if (SPICN0 & ERR_FLAGS_MASK) {  // check if any flag is set
      // Application callback
      if (spi0.err_callback != NULL)
        (*(spi0.err_callback))();
    }

    if (SPICN0 & ALL_FLAGS_MASK) {  // check if any flag is still set
      // Application callback
      if (spi0.isr_callback != NULL)
        (*(spi0.isr_callback))();
    }

    // If transfer complete flag is still set after app callback, use FIFO to handle
    if (SPICN0 & XFER_COMPLETE_FLAG) {

#if (SPI0_RXB_LEN > 0)
      // Receive handling
      data = spi0_recv();
      if (spi0.rxf != NULL) {
        fifo_put16(spi0.rxf, data);
      }
#endif

#if (SPI0_TXB_LEN > 0)
      // Transmit handling
      if ( (spi0.txf != NULL) && fifo_get16(spi0.txf, &data) )
        spi0_send(data);
      else {
        spi0_disable_interrupt();   // interrupt no longer needed

        // Application callback
        if (spi0.fifo_callback != NULL)
          (*(spi0.fifo_callback))();
      }
#endif

      SPICN0 &= ~XFER_COMPLETE_FLAG;  // clear SPIC flag
    }
#endif

  //*** SPI1 ***
#if (NUM_SPI > 1)
    if (SPICN1 & ERR_FLAGS_MASK) {  // check if any flag is set
      // Application callback
      if (spi1.err_callback != NULL)
        (*(spi1.err_callback))();
    }

    if (SPICN1 & ALL_FLAGS_MASK) {  // check if any flag is still set
      // Application callback
      if (spi1.isr_callback != NULL)
        (*(spi1.isr_callback))();   // call user callback
    }

    // If transfer complete flag is still set after app callback, use FIFO to handle
    if (SPICN1 & XFER_COMPLETE_FLAG) {

#if (SPI1_RXB_LEN > 0)
      // Receive handling
      data = spi1_recv();
      if (spi1.rxf != NULL) {
        fifo_put16(spi1.rxf, data);
      }
#endif

#if (SPI1_TXB_LEN > 0)
      // Transmit handling
      if ( (spi1.txf != NULL) && fifo_get16(spi1.txf, &data) )
        spi1_send(data);
      else {
        spi1_disable_interrupt();   // interrupt no longer needed

        // Application callback
        if (spi1.fifo_callback != NULL)
          (*(spi1.fifo_callback))();
      }
#endif

      SPICN1 &= ~XFER_COMPLETE_FLAG;  // clear SPIC flag
    }
#endif
}
